Repository navigation
Conversation
| if (state.visualMode === "line") { | ||
| const model = codeEditor.getModel(); | ||
| const end = Math.max(anchor.lineNumber, position.lineNumber); | ||
| const anchorEnd = model?.getLineMaxColumn(anchor.lineNumber) ?? anchor.column; |
There was a problem hiding this comment.
Non-blocking:
Problem: The Visual anchor survives model content changes without validation, although the source viewer refreshes the model through syncFileModel when files change.
Failure scenario: Enter linewise Visual mode on line 3, then let an agent rewrite the file to one line. The next motion calls getLineMaxColumn(3), throws “Illegal value for lineNumber”, and cannot update the selection. This reproduces with Monaco’s setValue path used by syncFileModel.
Suggested fix: Reset or validate Vim’s positional state when the editor model changes or its content is replaced, and dispose the corresponding listener with the controller.
There was a problem hiding this comment.
Fixed in fcb3a20. The controller listens for model content changes and resets anchors, Visual state, marks, jumps, pending commands and search state; the listener is disposed with the controller.
| consume(event); | ||
| count = ""; | ||
| anchor = currentPosition(); | ||
| update({ mode: "visual", visualMode: key === "V" ? "line" : "character" }); |
There was a problem hiding this comment.
Non-blocking:
Problem: Entering Visual mode changes only the label, and character selections use an exclusive end without translating Vim’s inclusive endpoint.
Failure scenario: V on a source line selects nothing, so the existing comment-on-selection action is unavailable; v followed by e on “one two” selects “on” rather than “one”. Both behaviors reproduce in Monaco.
Suggested fix: Render the initial character/line/block selection when entering Visual mode and translate the logical inclusive endpoints into Monaco ranges without losing the motion position.
There was a problem hiding this comment.
Fixed in fcb3a20. Entering Visual mode now renders the initial selection, and character/block ranges translate the logical inclusive Vim endpoint into Monaco’s exclusive range.
There was a problem hiding this comment.
Fixed in dc54005. Visual mode now renders an initial selection and translates the inclusive logical endpoint to Monaco’s exclusive range, so v on a character selects that character and v/e includes the full word.
| 1, | ||
| Math.min(model.getLineCount(), current.lineNumber + delta), | ||
| ); | ||
| setPosition({ |
There was a problem hiding this comment.
Non-blocking:
Problem: Page motions and mark jumps call setPosition directly in Visual mode, collapsing the selection while the mode remains Visual.
Failure scenario: With Vim enabled, v, l, Ctrl+D clears the selected range instead of extending it to the destination. Jumping to a mark with 'a has the same effect, so the resulting range cannot be used by Comment on selection. Reproduced with Monaco 0.57.0.
Suggested fix: Route page and mark motion destinations through applyPosition so Visual mode retains its anchor and updates its selection.
There was a problem hiding this comment.
Fixed in dc54005. Ctrl page motions and mark jumps now use applyPosition, preserving the logical Visual anchor and extending the selection instead of collapsing it.
Problem
ThinkRail's desktop Monaco source editor provided standard Monaco navigation only. Vim-oriented users lacked familiar motions, Visual selection, marks, jump history, and search while reviewing source files.
The source editor is intentionally read-only, so the feature must not turn source files into editable buffers.
Approach
Add a renderer-local, opt-in Vim controller around the existing desktop Monaco editor. Keep Vim disabled by default, preserve standard Monaco behavior while disabled, and expose only a narrow public hook so the web shell can toggle the focused editor from the command palette without coupling the renderer to shell internals.
The supported command set follows the high-value navigation subset documented by Vim and available in compact Linux Vim builds such as Debian
vim.tiny. Mutation operators, registers, clipboard, Ex commands, undo/redo, macros, terminal behavior, and mobile Pierre rendering remain out of scope because the source surface is read-only.Changes
gg/G,H/M/L,zt/zz/zb, page movement, counts, marks, and jump history./,?,n,Shift+N,*, and#search behavior.CHANGELOG.md, and durable spec updates.Screenshots
Before: desktop Monaco source editor on the base branch, Vim control absent.
After: same scenario and viewport with the Vim control enabled.
Related issues
Closes #1373
Checklist
bun run lint,bun run typecheck,bun run test—bun run lintand targeted package typechecks pass; rootbun run typecheckis blocked by installed Nodev22.23.2while the repository requires>=22.23.4;bun run testhas unrelated baseline/environment failures (one UI IME scan, one web focus-indicator scan, and five server git/process tests).bun run e2e)SPEC.md/ top-level specs updated to reflect any boundary, contract, or behavior change